﻿#region Using

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Vk.Methods.Common;
using Vk.Methods.Groups;
using Vk.Methods.Users;
using Vk.Methods.Wall;

#endregion

namespace Vk.Methods.News
{
    /// <summary>
    ///     Новости
    /// </summary>
    public class News
    {
        private readonly Api _api;

        public News(Api api)
        {
            _api = api;
        }

        /// <summary>
        ///     Запрещает показывать новости от заданных пользователей и групп в ленте новостей текущего пользователя.
        /// </summary>
        /// <param name="userIds">
        ///     Перечисленные через запятую идентификаторы друзей пользователя, новости от которых необходимо скрыть
        ///     из ленты новостей текущего пользователя.
        /// </param>
        /// <param name="groupIds">
        ///     Перечисленные через запятую идентификаторы групп пользователя, новости от которых необходимо скрыть
        ///     из ленты новостей текущего пользователя.
        /// </param>
        /// <returns>В случае успеха возвращает true. </returns>
        public async Task<bool> AddBan(IEnumerable<int> userIds = null, IEnumerable<int> groupIds = null)
        {
            var query = new ApiQuery("newsfeed.addBan")
                .Add("user_ids", userIds)
                .Add("group_ids", groupIds);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Разрешает показывать новости от заданных пользователей и групп в ленте новостей текущего пользователя.
        /// </summary>
        /// <param name="userIds">
        ///     Перечисленные через запятую идентификаторы друзей пользователя, новости от которых необходимо
        ///     вернуть в ленту новостей текущего пользователя.
        /// </param>
        /// <param name="groupIds">
        ///     Перечисленные через запятую идентификаторы групп пользователя, новости от которых необходимо вернуть
        ///     в ленту новостей текущего пользователя.
        /// </param>
        /// <returns>В случае успеха возвращает true. </returns>
        public async Task<bool> DeleteBan(IEnumerable<int> userIds = null, IEnumerable<int> groupIds = null)
        {
            var query = new ApiQuery("newsfeed.deleteBan")
                .Add("user_ids", userIds)
                .Add("group_ids", groupIds);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Метод позволяет удалить пользовательский список новостей
        /// </summary>
        /// <param name="listId">Числовой идентификатор списка </param>
        /// <returns>После успешного выполнения возвращает true</returns>
        public async Task<bool> DeleteList(int listId)
        {
            var query = new ApiQuery("newsfeed.deleteList")
                .Add("list_id", listId);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Возвращает данные, необходимые для показа списка новостей для текущего пользователя.
        /// </summary>
        /// <param name="sourceIds">Перечисленные через запятую иcточники новостей, новости от которых необходимо получить.</param>
        /// <param name="filters">Перечисленные через запятую названия списков новостей, которые необходимо получить. </param>
        /// <param name="startTime">
        ///     Время, в формате unixtime, начиная с которого следует получить новости для текущего
        ///     пользователя. Если параметр не задан, то он считается равным значению времени, которое было сутки назад.
        /// </param>
        /// <param name="endTime">
        ///     Время, в формате unixtime, до которого следует получить новости для текущего пользователя.
        ///     Если параметр не задан, то он считается равным текущему времени.
        /// </param>
        /// <param name="offset">
        ///     Указывает, начиная с какого элемента в данном промежутке времени необходимо получить новости. по
        ///     умолчанию 0.
        /// </param>
        /// <param name="count">
        ///     Указывает, какое максимальное число новостей следует возвращать, но не более 100. По умолчанию 50.
        ///     Для автоподгрузки Вы можете использовать возвращаемый данным методом параметр new_offset.
        /// </param>
        /// <param name="maxPhotos">Максимальное количество фотографий, информацию о которых необходимо вернуть. По умолчанию 5.</param>
        /// <param name="returnBanned">
        ///     true - включить в выдачу также скрытых из новостей пользователей. false - не возвращать
        ///     скрытых пользователей.
        /// </param>
        /// <param name="startFrom">
        ///     Идентификатор, необходимый для получения следующей страницы результатов. Значение, необходимое
        ///     для передачи в этом параметре, возвращается в поле ответа next_from.
        /// </param>
        /// <param name="fields">Список дополнительных полей для профилей и групп, которые необходимо вернуть.</param>
        public async Task<Newsfeed> Get(IEnumerable<string> sourceIds = null,
                                        ApiStringEnum<NewsType> filters = null,
                                        int? startTime = null,
                                        int? endTime = null,
                                        int? offset = null,
                                        string startFrom = null,
                                        int? count = null,
                                        int? maxPhotos = null,
                                        bool? returnBanned = null,
                                        IEnumerable<string> fields = null)
        {
            var query = new ApiQuery("newsfeed.get")
                .Add("source_ids", sourceIds)
                .Add("filters", filters)
                .Add("start_time", startTime)
                .Add("end_time", endTime)
                .Add("offset", offset)
                .Add("start_from", startFrom)
                .Add("count", count)
                .Add("max_photos", maxPhotos)
                .Add("fields", fields)
                .Add("return_banned", returnBanned);

            var resp = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed ? new Newsfeed(resp) : null;
        }

        /// <summary>
        ///     Возвращает список пользователей и групп, которые текущий пользователь скрыл из ленты новостей.
        /// </summary>
        /// <returns>
        ///     В случае успеха возвращает объект, в котором содержатся поля groups и members. В поле groups содержится массив
        ///     идентификаторов групп, которые пользователь скрыл из ленты новостей. В поле members содержится массив
        ///     идентификаторов друзей, которые пользователь скрыл из ленты новостей.
        /// </returns>
        public async Task<BannedInfo> GetBanned()
        {
            var query = new ApiQuery("newsfeed.getBanned");

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed ? new BannedInfo(result) : null;
        }

        /// <summary>
        ///     Возвращает список пользователей и групп, которые текущий пользователь скрыл из ленты новостей.
        /// </summary>
        /// <param name="fields">Поля профилей, которые необходимо вернуть. См. Описание полей параметра fields</param>
        /// <param name="nameCase">Падеж для склонения имени и фамилии пользователя. </param>
        /// <returns>
        ///     В случае успеха возвращает объект, в котором содержатся поля groups и members. В поле groups содержится массив
        ///     идентификаторов групп, которые пользователь скрыл из ленты новостей. В поле members содержится массив
        ///     идентификаторов друзей, которые пользователь скрыл из ленты новостей.
        /// </returns>
        public async Task<BannedInfoExtended> GetBannedExtended(IEnumerable<string> fields, string nameCase = null)
        {
            if (fields == null)
            {
                throw new ArgumentNullException(nameof(fields));
            }
            var query = new ApiQuery("newsfeed.getBanned")
                .Add("extended", true)
                .Add("fields", fields)
                .Add("name_case", nameCase);

            var resp = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed ? new BannedInfoExtended(resp) : null;
        }

        /// <summary>
        ///     Возвращает данные, необходимые для показа раздела комментариев в новостях пользователя.
        /// </summary>
        /// <param name="filters">Перечисленные через запятую типы объектов, изменения комментариев к которым нужно вернуть.</param>
        /// <param name="startTime">
        ///     Время, в формате unixtime, начиная с которого следует получить новости для текущего
        ///     пользователя. Если параметр не задан, то он считается равным значению времени, которое было сутки назад.
        /// </param>
        /// <param name="endTime">
        ///     Время, в формате unixtime, до которого следует получить новости для текущего пользователя.
        ///     Если параметр не задан, то он считается равным текущему времени.
        /// </param>
        /// <param name="count">Указывает, какое максимальное число новостей следует возвращать, но не более 100. По умолчанию 30.</param>
        /// <param name="lastCommentsCount">
        ///     Количество комментариев к записям, которые нужно получить. По умолчанию 0, максимальное
        ///     значение 10
        /// </param>
        /// <param name="reposts">
        ///     Идентификатор объекта, комментарии к репостам которого необходимо вернуть, например wall1_45486.
        ///     Если указан данный параметр, параметр filters указывать не обзательно.
        /// </param>
        /// <param name="startFrom">
        ///     Идентификатор, необходимый для получения следующей страницы результатов. Значение, необходимое
        ///     для передачи в этом параметре, возвращается в поле ответа next_from.
        /// </param>
        /// <param name="fields">Список дополнительных полей профилей, которые необходимо вернуть.</param>
        public async Task<ItemsNextProfilesGroups<NewsEntity>> GetComments(ApiStringEnum<NewsType> filters = null,
                                                                           int? startTime = null,
                                                                           string startFrom = null,
                                                                           int? endTime = null,
                                                                           int? count = null,
                                                                           ushort? lastCommentsCount = null,
                                                                           string reposts = null,
                                                                           IEnumerable<string> fields = null)
        {
            var query = new ApiQuery("newsfeed.getComments")
                .Add("start_from", startFrom)
                .Add("filters", filters)
                .Add("start_time", startTime)
                .Add("end_time", endTime)
                .Add("count", count)
                .Add("last_comments_count", lastCommentsCount)
                .Add("fields", fields)
                .Add("reposts", reposts);

            var resp = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return resp.ChildNodes.Any()
                           ? new ItemsNextProfilesGroups<NewsEntity>(resp, node => new NewsEntity(node))
                           : null;
            }
            return null;
        }

        /// <summary>
        ///     Возвращает пользовательские списки новостей
        /// </summary>
        /// <param name="listIds">Идентификаторы списков. </param>
        /// <param name="extended">true — вернуть дополнительную информацию о списке (значения source_ids и no_reposts). </param>
        public async Task<ListCount<NewsListInfo>> GetLists(IEnumerable<int> listIds = null, bool? extended = null)
        {
            var query = new ApiQuery("newsfeed.getLists")
                .Add("list_ids", listIds)
                .Add("extended", extended);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed
                       ? new ListCount<NewsListInfo>(result.Int("count").Value,
                                                     result.ChildNodes.Select(x => new NewsListInfo(x)).ToList())
                       : null;
        }

        /// <summary>
        ///     Возвращает список записей пользователей на своих стенах, в которых упоминается указанный пользователь.
        /// </summary>
        /// <param name="ownerId">Идентификатор группы или сообщества </param>
        /// <param name="startTime">
        ///     Время в формате unixtime начиная с которого следует получать упоминания о пользователе.
        ///     Если параметр не задан, то будут возвращены все упоминания о пользователе, если не задан параметр end_time, в
        ///     противном случае упоминания с учетом параметра end_time.
        /// </param>
        /// <param name="endTime">
        ///     Время, в формате unixtime, до которого следует получать упоминания о пользователе.
        ///     Если параметр не задан, то будут возвращены все упоминания о пользователе, если не задан параметр start_time, в
        ///     противном случае упоминания с учетом параметра start_time.
        /// </param>
        /// <param name="offset">Смещение, необходимое для выборки определенного подмножества новостей. По умолчанию 0. </param>
        /// <param name="count">
        ///     Количество возвращаемых записей. Если параметр не задан, то считается, что он равен 20.
        ///     Максимальное значение параметра 50.
        /// </param>
        public async Task<ListCount<WallPost>> GetMentions(int? ownerId = null,
                                                             int? startTime = null,
                                                             int? endTime = null,
                                                             int? offset = null,
                                                             int? count = null)
        {
            var query = new ApiQuery("newsfeed.getMentions")
                .Add("owner_id", ownerId)
                .Add("offset", offset)
                .Add("count", count)
                .Add("start_time", startTime)
                .Add("end_time", endTime);

            var resp = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                if (!resp.ChildNodes.Any())
                {
                    return null;
                }

                return new ListCount<WallPost>(resp.Int("count").Value,
                                                 resp.SelectNodes("items/*").Select(y => new WallPost(y)).ToList());
            }
            return null;
        }

        /// <summary>
        ///     Получает список новостей, рекомендованных пользователю
        /// </summary>
        /// <param name="startTime">
        ///     Время в формате unixtime, начиная с которого следует получить новости для текущего
        ///     пользователя. Если параметр не задан, то он считается равным значению времени, которое было сутки назад.
        /// </param>
        /// <param name="endTime">
        ///     Время в формате unixtime, до которого следует получить новости для текущего пользователя.
        ///     Если параметр не задан, то он считается равным текущему времени.
        /// </param>
        /// <param name="offset">
        ///     Указывает, начиная с какого элемента в данном промежутке времени необходимо получить новости. По
        ///     умолчанию 0. Для автоподгрузки Вы можете использовать возвращаемый данным методом параметр new_offset
        /// </param>
        /// <param name="startFrom">
        ///     Идентификатор, необходимый для получения следующей страницы результатов. Значение, необходимое
        ///     для передачи в этом параметре, возвращается в поле ответа next_from.
        /// </param>
        /// <param name="count">Указывает, какое максимальное число новостей следует возвращать, но не более 100. По умолчанию 50</param>
        /// <param name="maxPhotos">Максимальное количество фотографий, информацию о которых необходимо вернуть. По умолчанию 5. </param>
        public async Task<Newsfeed> GetRecommendations(int? startTime = null,
                                                       int? endTime = null,
                                                       int? offset = null,
                                                       string startFrom = null,
                                                       int? count = null,
                                                       int? maxPhotos = null)
        {
            var query = new ApiQuery("newsfeed.getRecommended")
                .Add("start_time", startTime)
                .Add("end_time", endTime)
                .Add("offset", offset)
                .Add("start_from", startFrom)
                .Add("count", count)
                .Add("max_photos", maxPhotos);

            var resp = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                return !resp.ChildNodes.Any() ? null : new Newsfeed(resp);
            }
            return null;
        }

        /// <summary>
        ///     Получает список новостей, рекомендованных пользователю.
        /// </summary>
        /// <param name="startTime">
        ///     Время в формате unixtime, начиная с которого следует получить новости для текущего
        ///     пользователя. Если параметр не задан, то он считается равным значению времени, которое было сутки назад.
        /// </param>
        /// <param name="endTime">
        ///     Время в формате unixtime, до которого следует получить новости для текущего пользователя. Если
        ///     параметр не задан, то он считается равным текущему времени.
        /// </param>
        /// <param name="startFrom">
        ///     Идентификатор, необходимый для получения следующей страницы результатов. Значение, необходимое
        ///     для передачи в этом параметре, возвращается в поле ответа next_from.
        /// </param>
        /// <param name="count">Указывает, какое максимальное число новостей следует возвращать, но не более 100. По умолчанию 50. </param>
        /// <param name="maxPhotos">Максимальное количество фотографий, информацию о которых необходимо вернуть. По умолчанию 5. </param>
        /// <param name="fields">Список дополнительных полей профилей, которые необходимо вернуть.</param>
        public async Task<Newsfeed> GetRecommended(int? startTime = null,
                                                   int? endTime = null,
                                                   string startFrom = null,
                                                   int? count = null,
                                                   int? maxPhotos = null,
                                                   IEnumerable<string> fields = null)
        {
            var query = new ApiQuery("newsfeed.getRecomended")
                .Add("start_time", startTime)
                .Add("end_time", endTime)
                .Add("start_from", startFrom)
                .Add("count", count)
                .Add("max_photos", maxPhotos)
                .Add("fields", fields);

            var resp = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed ? new Newsfeed(resp) : null;
        }

        /// <summary>
        ///     Возвращает сообщества, на которые пользователю рекомендуется подписаться
        /// </summary>
        /// <param name="count">Количество сообществ или пользователей, которое необходимо вернуть</param>
        /// <param name="offset">Отсуп, необходимый для выборки определенного подмножества сообществ или пользователей</param>
        /// <param name="shuffle">Перемешивать ли возвращаемый список</param>
        /// <param name="fields">Список дополнительных полей, которые необходимо вернуть.</param>
        public async Task<UsersGroupsList> GetSuggestedSources(int? count = null,
                                                               int? offset = null,
                                                               bool? shuffle = null,
                                                               IEnumerable<string> fields = null)
        {
            var query = new ApiQuery("newsfeed.getSuggestedSources")
                .Add("count", count)
                .Add("offset", offset)
                .Add("shuffle", shuffle)
                .Add("fields", fields);

            var resp = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                if (!resp.ChildNodes.Any())
                    return null;
                var r = new UsersGroupsList();
                r.Groups = resp.SelectNodes("//group").Select(y => new Group(y)).ToList();
                r.Users = resp.SelectNodes("//user").Select(y => new BaseUser(y)).ToList();
                return r;
            }
            return null;
        }

        /// <summary>
        ///     Позволяет скрыть объект из ленты новостей.
        /// </summary>
        /// <param name="itemId">Идентификатор объекта. </param>
        /// <param name="ownerId">Идентификатор владельца объекта (пользователь или сообщество).</param>
        /// <param name="type">Тип объекта. </param>
        /// <returns>В результате успешного выполнения возвращает true.</returns>
        public async Task<bool> IgnoreItem(int itemId, int ownerId, ApiStringEnum<NewsItemType> type)
        {
            if (type == null)
                throw new ArgumentNullException(nameof(type));

            var query = new ApiQuery("newsfeed.ignoreItem")
                .Add("item_id", itemId)
                .Add("type", type.Value)
                .Add("owner_id", ownerId);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Метод позволяет создавать или редактировать пользовательские списки для просмотра новостей.
        /// </summary>
        /// <param name="title">Название списка. </param>
        /// <param name="listId">Числовой идентификатор списка (если не передан, будет назначен автоматически). </param>
        /// <param name="sourceIds">
        ///     Идентификаторы пользователей и сообществ, которые должны быть включены в список. Идентификаторы
        ///     сообществ нужно указывать со знаком «минус».
        /// </param>
        /// <param name="noReposts">Нужно ли отображать копии постов в списке (1 — не нужно). </param>
        /// <returns>После успешного выполнения возвращает идентификатор созданного или отредактированного списка.</returns>
        public async Task<int> SaveList(string title,
                                        int? listId = null,
                                        IEnumerable<int> sourceIds = null,
                                        bool? noReposts = null)
        {
            if (title == null)
                throw new ArgumentNullException(nameof(title));

            var query = new ApiQuery("newsfeed.saveList")
                .Add("title", title)
                .Add("list_id", listId)
                .Add("source_ids", sourceIds)
                .Add("no_reposts", noReposts);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed ? result.Int().Value : -1;
        }

        /// <summary>
        ///     Возвращает результаты поиска по статусам.
        /// </summary>
        /// <param name="q">Поисковой запрос, по которому необходимо получить результаты.</param>
        /// <param name="count">Указывает, какое максимальное число записей следует возвращать, но не более 100.</param>
        /// <param name="startFrom">
        ///     Идентификатор, необходимый для получения следующей страницы результатов. Значение, необходимое
        ///     для передачи в этом параметре, возвращается в поле ответа next_from.
        /// </param>
        /// <param name="startTime">
        ///     Время, в формате unixtime, начиная с которого следует получить новости для текущего
        ///     пользователя. Если параметр не задан, то он считается равным значению времени, которое было сутки назад.
        /// </param>
        /// <param name="endTime">
        ///     Время, в формате unixtime, до которого следует получить новости для текущего пользователя. Если
        ///     параметр не задан, то он считается равным текущему времени.
        /// </param>
        /// <param name="startId">
        ///     Строковый id последней полученной записи. (Возвращается в результатах запроса, для того, чтобы
        ///     исключить из выборки нового запроса уже полученные записи)
        /// </param
        /// <param name="longitude">
        ///     Географическая долгота точки, в радиусе от которой необходимо производить поиск, заданная в градусах
        ///     (от -180 до 180)
        /// </param>
        /// <param name="latitude">
        ///     Географическая широта точки, в радиусе от которой необходимо производить поиск, заданная в градусах
        ///     (от -90 до 90)
        /// </param>
        public async Task<ListCount<BaseNewsEntity>> Search(string q = null,
                                                            int? count = null,
                                                            string startFrom = null,
                                                            int? startTime = null,
                                                            int? endTime = null,
                                                            int? startId = null,
                                                            double? latitude = null,
                                                            double? longitude = null)
        {
            var query = new ApiQuery("newsfeed.search", true)
                .Add("q", q)
                .Add("count", count)
                .Add("start_from", startFrom)
                .Add("start_time", startTime)
                .Add("end_time", endTime)
                .Add("start_id", startId)
                .Add("latitude", latitude)
                .Add("longitude", longitude);

            var resp = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                var items = resp.SelectNodes("items/*");
                if (items != null)
                {
                    return
                        new ListCount<BaseNewsEntity>(resp.Int("count").Value, items
                                                                                   .Select(y => new BaseNewsEntity(y))
                                                                                   .ToList());
                }
            }
            return null;
        }

        /// <summary>
        ///     Возвращает результаты поиска по статусам + информацию о пользователе или группе, разместившей запись.
        /// </summary>
        /// <param name="q">Поисковой запрос, по которому необходимо получить результаты.</param>
        /// <param name="count">Указывает, какое максимальное число записей следует возвращать, но не более 100.</param>
        /// <param name="startFrom">
        ///     Идентификатор, необходимый для получения следующей страницы результатов. Значение, необходимое
        ///     для передачи в этом параметре, возвращается в поле ответа next_from.
        /// </param>
        /// <param name="startTime">
        ///     Время, в формате unixtime, начиная с которого следует получить новости для текущего
        ///     пользователя. Если параметр не задан, то он считается равным значению времени, которое было сутки назад.
        /// </param>
        /// <param name="endTime">
        ///     Время, в формате unixtime, до которого следует получить новости для текущего пользователя. Если
        ///     параметр не задан, то он считается равным текущему времени.
        /// </param>
        /// <param name="startId">
        ///     Строковый id последней полученной записи. (Возвращается в результатах запроса, для того, чтобы
        ///     исключить из выборки нового запроса уже полученные записи)
        /// </param>
        /// <param name="longitude">
        ///     Географическая долгота точки, в радиусе от которой необходимо производить поиск, заданная в градусах
        ///     (от -180 до 180)
        /// </param>
        /// <param name="latitude">
        ///     Географическая широта точки, в радиусе от которой необходимо производить поиск, заданная в градусах
        ///     (от -90 до 90)
        /// </param>
        public async Task<List<SearchExtendedResult>> SearchExtended(string q = null,
                                                                     int? count = null,
                                                                     string startFrom = null,
                                                                     int? startTime = null,
                                                                     int? endTime = null,
                                                                     int? startId = null,
                                                                     double? latitude = null,
                                                                     double? longitude = null)
        {
            var query = new ApiQuery("newsfeed.search")
                .Add("extended", 1)
                .Add("q", q)
                .Add("count", count)
                .Add("start_from", startFrom)
                .Add("start_time", startTime)
                .Add("end_time", endTime)
                .Add("start_id", startId)
                .Add("latitude", latitude)
                .Add("longitude", longitude);

            var resp = await _api.Manager.Execute(query);
            if (_api.Manager.MethodSuccessed)
            {
                var items = resp.SelectNodes("items/*");
                if (items != null)
                {
                    return
                        items
                            .Select(y => new SearchExtendedResult(y))
                            .ToList();
                }
            }
            return null;
        }

        /// <summary>
        ///     Позволяет вернуть ранее скрытый объект в ленту новостей.
        /// </summary>
        /// <param name="itemId">Идентификатор объекта. </param>
        /// <param name="ownerId">Идентификатор владельца объекта (пользователь или сообщество).</param>
        /// <param name="type">Тип объекта. </param>
        /// <returns>В результате успешного выполнения возвращает true.</returns>
        public async Task<bool> UnignoreItem(int itemId, int ownerId, ApiStringEnum<NewsItemType> type)
        {
            if (type == null)
                throw new ArgumentNullException(nameof(type));

            var query = new ApiQuery("newsfeed.unignoreItem")
                .Add("item_id", itemId)
                .Add("type", type.Value)
                .Add("owner_id", ownerId);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Отписывает текущего пользователя от комментариев к заданному объекту
        /// </summary>
        /// <param name="itemId">Идентификатор объекта</param>
        /// <param name="type">Тип объекта, от комментариев к которому необходимо отписаться.</param>
        /// <param name="ownerId">Идентификатор владельца объекта</param>
        /// <returns>После успешного выполнения возвращает true</returns>
        public async Task<bool> Unsubscribe(int itemId, CommentType type, int? ownerId = null)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            var query = new ApiQuery("newsfeed.unsubscribe")
                .Add("item_id", itemId)
                .Add("type", type.StringValue)
                .Add("owner_id", ownerId);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }
    }
}